//
// Created by 李康 on 15/12/9.
//

#include "aprioriImpl.h"
#include <sstream>
using namespace std;

SuperItemSet genL1(const string inputfilename, map<ItemSet, int> &FreItemSupport, const int min_sup) {
    ifstream inputfile(inputfilename.c_str());
    string line;
    stringstream ss;
    SuperItemSet freItem;
    string word;
    while (getline(inputfile, line)) {
        ss.str(line);
        while (ss >> word) {
            ItemSet temp;
            temp.insert(word);
            freItem.insert(temp);
        }
        ss.clear();
    }
    inputfile.close();
    return scanDB(inputfilename, freItem, FreItemSupport, min_sup);
}

SuperItemSet scanDB(const string inputfilename, const SuperItemSet &Candidate, map<ItemSet, int> &FreItemSupport, const int min_sup) {
    map<ItemSet, int> CanSupport = calSupport(inputfilename, Candidate);
    SuperItemSet ret;
    for (map<ItemSet, int>::iterator iter = CanSupport.begin(); iter != CanSupport.end(); ++iter) {
        if (iter->second >= min_sup) {
            ret.insert(iter->first);
            FreItemSupport.insert(make_pair(iter->first, iter->second));
        }
    }
    return ret;
}

map<ItemSet, int> calSupport(const string inputfilename, const SuperItemSet &Candidate) {
    ifstream inputfile(inputfilename);
    string line;
    bool flag;
    map<ItemSet, int> CanSupport;
    while (getline(inputfile, line)) {
        for (SuperItemSetIter iter = Candidate.begin(); iter != Candidate.end(); ++iter) {
            flag = true;
            for (ItemSetIter iter1 = iter->begin(); iter1 != iter->end(); ++iter1) {
                if (line.find(*iter1) == -1) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                CanSupport[*iter] += 1;
            }
        }
    }
    inputfile.close();
    return CanSupport;
}

SuperItemSet genCk(const SuperItemSet &freItemSet) {
    SuperItemSet ret;
    stringstream ss;
    int hour1;
    int hour2;
    string n1;
    string n2;
    string hour_str;
    ItemSet temp;
    for (SuperItemSetIter iter = freItemSet.begin(); iter != freItemSet.end(); ++iter) {
        SuperItemSetIter tempiter = iter;
        ++tempiter;
        for (SuperItemSetIter iter1 = tempiter; iter1 != freItemSet.end(); ++iter1) {
            ItemSet s1(++(iter->begin()), iter->end());
            ItemSet s2(iter1->begin(), --(iter1->end()));
            n1 = *(--((*iter).end()));
            n2 = *(--((*iter1).end()));
            hour_str = n1.substr(0, 2);
            ss.str(hour_str);
            ss >> hour1;
            ss.clear();
            hour_str = n2.substr(0, 2);
            ss.str(hour_str);
            ss >> hour2;
            ss.clear();
            if (s1 == s2 && hour2 - hour1 == 1) {
                temp = *iter;
                temp.insert(n2);
                bool bb = hasInfrequent(temp, freItemSet);
                if (!bb) {
                    ret.insert(temp);
                }
            }
        }
    }
    return ret;
}

bool hasInfrequent(const ItemSet &itemSet, const SuperItemSet &FreItemSet) {
    SuperItemSet subSets = genSubSets(itemSet);
    for (SuperItemSetIter iter = subSets.begin(); iter != subSets.end(); ++iter) {
        if (FreItemSet.find(*iter) == FreItemSet.end()) {
            return true;
        }
    }
    return false;
}

//because sequencial itemset, so only two subsets is generated
//for example, subsets of  {00s, 01u, 02d} are {00s, 01u} {01u, 02d}
SuperItemSet genSubSets(const ItemSet &itemSet) {
    SuperItemSet subSets;
    ItemSet temp;
    ItemSetIter iter = --itemSet.end();
    temp = itemSet;
    temp.erase(*itemSet.begin());
    subSets.insert(temp);
    temp = itemSet;
    temp.erase(*iter);
    subSets.insert(temp);
    /*
    for (ItemSetIter iter = itemSet.begin(); iter != itemSet.end(); ++iter) {
        temp = itemSet;
        temp.erase(*iter);
        subSets.insert(temp);
    }*/
    return subSets;
}

void showRule(ofstream &outfile, const SuperItemSet &FreItemSet, map<ItemSet, int> &FreItemSupport, const double min_con) {
    ItemSet temp;
    double con;
    for (SuperItemSetIter iter = FreItemSet.begin(); iter != FreItemSet.end(); ++iter) {
        temp = *iter;
        temp.erase(*(--iter->end()));
        con = (double) FreItemSupport[*iter] / FreItemSupport[temp];
        if (con >= min_con) {
            for (ItemSetIter iter1 = temp.begin(); iter1 != temp.end(); ++iter1) {
                outfile << *iter1 << " ";
            }
            outfile << "-> ";
            outfile << *(--iter->end()) << "  support : " << FreItemSupport[*iter] << "  confidence : " << con << endl;
        }
    }
}